class GPScp02
  attr_accessor :host_challenge
  attr_accessor :kmc_id
  attr_accessor :csn 
  attr_accessor :kmc_version 
  attr_accessor :scp_id
  attr_accessor :sequence_counter
  attr_accessor :card_challenge
  attr_accessor :cryptogram
  attr_accessor :public_derive_factor
  attr_accessor :dek_session_key
  attr_accessor :state
  attr_accessor :security_level
  
  def initialize card,crypto
    @crypto = crypto
    @card = card
    @state = :SC_CLOSE
    @security_level = :no_sec
  end
  
  #
  #
  #
  def initialize_update security_domain = ByteString.new('a000000003000000',HEX)
    #select security domain
    response,sw = @card.select(security_domain)
    assert(sw == ByteString.new('9000',HEX),"select security domain failed")
    
    @host_challenge = @crypto.generateRandom 8
    response,sw = @card.initialize_update @host_challenge
    assert(sw == ByteString.new('9000',HEX),"initialize update failed")
    
    @kmc_id = response.bytes(0, 6)
    @csn = response.bytes(6, 4)
    @public_derive_factor = response.bytes(4, 6)
    @kmc_version = response.bytes(10, 1)
    @scp_id = response.bytes(11, 1)
    @sequence_counter =  response.bytes(12,2)
    @card_challenge = response.bytes(14,6)
    @cryptogram = response.bytes(20,8)
    
    @state = :SC_INITIALIZE
  end
  
  #
  #
  #
  def external_authenticate base_key = ByteString.new('404142434445464748494A4B4C4D4E4F',HEX)
    kmc = Key.new
    kmc.setComponent( Key.DES, base_key)
    #get kmc_enc from KMC
    kmc_enc = @crypto.get_derive_key(kmc, @public_derive_factor, ByteString.new("F001", HEX), ByteString.new("0F01", HEX))
    #get kmc_mac from KMC
    kmc_mac = @crypto.get_derive_key(kmc, @public_derive_factor, ByteString.new("F002", HEX), ByteString.new("0F02", HEX))
    #get kmc_kek from KMC
    kmc_kek = @crypto.get_derive_key(kmc, @public_derive_factor, ByteString.new("F003", HEX), ByteString.new("0F03", HEX))
    #get ksc_enc from kmc_enc
    bsTail = ByteString.new("000000000000000000000000", HEX);
    bsPad = ByteString.new("0182", HEX);
    ksc_enc = @crypto.get_session_key(kmc_enc,bsPad,@sequence_counter,bsTail);
    #get ksc_mac from kmc_mac
    bsPad = ByteString.new("0101", HEX);
    ksc_mac = @crypto.get_session_key(kmc_mac,bsPad,@sequence_counter,bsTail);
    #get ksc_kek from kmc_kek
    bsPad = ByteString.new("0181", HEX);
    @dek_session_key = @crypto.get_session_key(kmc_kek,bsPad,@sequence_counter,bsTail);
    #External Authenticate
    challenge = @sequence_counter.concat(@card_challenge).concat(@host_challenge)
    response,sw = @card.external_authenticate(@crypto,ksc_enc,ksc_mac,challenge)
    assert(sw == ByteString.new('9000',HEX),"external authenticate failed")
    
    @state = :SC_OPEN  
  end
  
  def encryptDek data,meth
    if @state == :SC_OPEN
      return @crypto.encrypt(@dek_session_key,meth, data)
    else 
      return nil
    end
  end
  
end
